const decompRules = [
  {
    desc: '本年利润特别拆分',
    match: ({succ}) => succ.map(({curr:{name}}) => name).includes('本年利润'),
    opts: {
      type: 'SINGLE',
      deductFunc: (({curr:{name}}) => name === '本年利润')
    }
  },
  {
    match: () => true,
    opts: {
      type: 'ALTERNATE',
    }
  }
]

/**
 * # decomposeVouchers
 * # 分解凭证
 * 
 * 此过程完成两件事，首先按照规则将凭证内分录拆解为正则分录（一借一贷），然后将
 * 所有发生分录及对方分录的Identity设为科目余额表的Identity
 * 
 * 
 * @param {Category} category 科目余额表
 * @param {Cask<Voucher>} journalVouchers 按凭证归集的序时账
 * @param {Array} decompRules 分解凭证规则
 */

const decomposeVouchers = (category, journalVouchers) => {

  // 由于凭证内所有的分录的发生科目均为末级科目，因此从余额表中找到
  // 对应的末级科目并建立一个字典。
  const mergedCateEnds = category
    .unnestTo()
    .all('succ.length', 0);

  const mergedCateEndMap = mergedCateEnds
    .grip('curr.code')
    .map(([k, [{curr}]]) => [k, curr]);

  // 将在科目余额表中设ref，使得Identity可以引用科目余额表项目
  for (let cateEndEntry of mergedCateEnds) {
    const {curr} = cateEndEntry;
    curr.setRef(cateEndEntry);
    curr.mark = true;
  }
  
  for (let v = 0; v < journalVouchers.length; v++) {

    const voucher = journalVouchers[v];

    // 按规则分解凭证。分解规则的最后一条必须适用于所有凭证，即
    // match(voucher)的结果总为true。

    for (let i = 0; i < decompRules.length; i++) {
      const {match, desc, opts} = decompRules[i];
      if (match(voucher)) {
        voucher.decompose(opts);
        voucher.attr.decompType = opts.type;
        break;
      }
    }

    // 然后将末级科目的curr写入序时账的curr和dest。因为序时账无论
    // 发生科目还是对方科目都来自于末级科目。

    for (let entry of voucher.succ) {
      try {
        const {curr: {code: currCode}, dest: {code: destCode}} = entry;
        const curr = mergedCateEndMap.get(currCode);
        const dest = mergedCateEndMap.get(destCode);
        Object.assign(entry, {curr, dest});
  
        entry.attr.level = 'ENTRY';
      } catch {
        console.warn(voucher);
      }
    }

  }

}

export default decomposeVouchers;